package logservice

import (
	"errors"
	"fmt"
	"path"
	"runtime"

	"strings"
	"time"
)

type LogLevel uint16

const (
	UNKOWN LogLevel = iota
	DEBUG
	TRACE
	INFO
	WARNING
	ERROR
	FATAL
)

func parseLevel(s string) (LogLevel, error) {
	s = strings.ToLower(s) //转化为小写
	switch s {
	case "debug":
		return DEBUG, nil
	case "trace":
		return TRACE, nil
	case "warning":
		return WARNING, nil
	case "fatal":
		return FATAL, nil
	case "error":
		return ERROR, nil
	case "info":
		return INFO, nil
	default:
		err := errors.New("无效的日志级别")
		return UNKOWN, err

	}
}

//自定义日志库
type Logger struct {
	Level LogLevel
}

func logLevelToStr(l LogLevel) string {
	switch l {
	case TRACE:
		return "TRACE"
	case WARNING:
		return "WARNING"
	case FATAL:
		return "FATAL"
	case INFO:
		return "INFO"
	case ERROR:
		return "ERROR"
	}
	return "DEBUG"
}

func NewLog(levelStr string) Logger {
	level, err := parseLevel(levelStr)
	if err != nil {
		panic(err)

	}
	return Logger{
		Level: level,
	}
}

func (l Logger) enable(logLevel LogLevel) bool {
	return logLevel >= l.Level
}

func (l Logger) printLog(format string, lv LogLevel, a ...interface{}) {
	msg := fmt.Sprintf(format, a...)
	now := time.Now()
	funcName, fileName, lineNo := getInfo(3)
	fmt.Printf("[%s][%s](%s:%s:%d)%s\n", now.Format("2006-01-02 15:04:05"), logLevelToStr(lv), funcName, fileName, lineNo, msg)
}

func (l Logger) Debug(format string, a ...interface{}) {

	if l.enable(DEBUG) {
		l.printLog(format, DEBUG, a...)
	}
}

func (l Logger) Info(format string, a ...interface{}) {

	if l.enable(INFO) {
		l.printLog(format, INFO, a...)
	}
}

func (l Logger) Warning(format string, a ...interface{}) {

	if l.enable(WARNING) {
		l.printLog(format, WARNING, a...)
	}
}

func (l Logger) Trace(format string, a ...interface{}) {

	if l.enable(TRACE) {
		l.printLog(format, TRACE, a...)
	}
}

func (l Logger) Error(format string, a ...interface{}) {

	if l.enable(ERROR) {
		l.printLog(format, ERROR, a...)
	}
}

func (l Logger) Fatal(format string, a ...interface{}) {

	if l.enable(FATAL) {
		l.printLog(format, FATAL, a...)
	}
}

func getInfo(skip int) (funcName, fileName string, lineNo int) {
	pc, file, lineNo, ok := runtime.Caller(skip)
	if !ok {
		fmt.Printf("runtime.Caller() failed\n")
	}
	funcName = runtime.FuncForPC(pc).Name()
	fileName = path.Base(file)
	return
}
